﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Rewrite;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;

using Wangkanai.Detection;
using Wangkanai.Responsive;

using WqLunTan.BLL;
using WqLunTan.DBContext;
using WqLunTan.Filters;
using WqLunTan.Models.DataBase;
using WqLunTan.Reply;

namespace WqLunTan
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            // Add responsive services.
            services.AddResponsive()
                .AddViewSuffix()
                .AddViewSubfolder();

            services.AddMvc(x =>
            {
                x.Filters.Add<HttpGlobalExceptionFilter>();
            });

            services.AddDbContext<MySqlDbContext>(opt =>
            {
                opt.UseMySql(Configuration.GetValue<string>("mysql_connstr"));
            });
            services.AddMemoryCache();
            services.AddSession(x =>
            {
                x.IdleTimeout = TimeSpan.FromMinutes(30);
            });

            // 添加授权模块
            services.AddIdentity<WqUser, WqUserRole>().AddEntityFrameworkStores<MySqlDbContext>().AddDefaultTokenProviders();
            // 修改Identity配置
            services.Configure<IdentityOptions>(x =>
            {
                x.Password.RequireLowercase = false;
                x.Password.RequireNonAlphanumeric = false;
                x.Password.RequireUppercase = false;
            });

            // 添加 jwt 认证
            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = "JwtBearer";
                options.DefaultChallengeScheme = "JwtBearer";
            }).AddJwtBearer("JwtBearer", jwtBearerOptions =>
            {
                jwtBearerOptions.Events = new JwtBearerEvents()
                {
                    OnMessageReceived = context =>
                    {
                        if (context.Request.Method.Equals("get", StringComparison.InvariantCultureIgnoreCase) && context.Request.Cookies.TryGetValue("token", out var val))
                        {
                            context.Token = val;   // 从cookie中获取, 主要用于get请求, 浏览器关闭cookie过期, 也可以设置一个长期的cookie
                            }
                        if (context.Request.Method.Equals("post", StringComparison.InvariantCultureIgnoreCase) && context.Request.Headers.TryGetValue("Authorization", out var auth))
                        {
                            context.Token = auth.ToString().Split(' ').LastOrDefault();    // 从请求头中获取, 主要用于post请求
                            }
                        return Task.CompletedTask;
                    }
                };

                jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetValue<string>("jwtConfig:jwtSecret"))),

                    ValidateIssuer = true,
                    ValidIssuer = Configuration.GetValue<string>("jwtConfig:issuer"),

                    ValidateAudience = true,
                    ValidAudience = Configuration.GetValue<string>("jwtConfig:audience"),

                    ValidateLifetime = true, //validate the expiration and not before values in the token

                    ClockSkew = TimeSpan.FromMinutes(5) //5 minute tolerance for the expiration date
                };
            });

            services.AddScoped<IReply, WxUidReply>();
            services.AddScoped<IReply, HomePageReply>();
            services.AddScoped<IReply, ScanReply>();
            services.AddScoped<IReply, SubscribeReply>();
            services.AddScoped<IReply, UnSubscibeReply>();
            services.AddScoped<IReply, NormalReply>();
            services.AddScoped<IReply, MessageReply>();
            services.AddScoped<LayoutDataServices>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseBrowserLink();
                app.UseDeveloperExceptionPage();
                Console.WriteLine("debug模式不强制启用https.");
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");

                var options = new RewriteOptions().AddRedirectToHttpsPermanent();
                app.UseRewriter(options);
            }

            app.UseStaticFiles();
            //验证中间件
            app.UseAuthentication();
            app.UseSession();


            app.UseResponsive(new ResponsiveOptions
            {
                TabletDefault = DeviceType.Mobile
            });    // 视图自动切换模块

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                name: "areas",
                template: "{area:exists}/{controller=Account}/{action=Login}/{id?}");

                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");
            });
        }
    }
}
